//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 1995-1999  Microsoft Corporation

Module Name:

rilndis.h

Abstract:


Notes:


--*/

#pragma once
#include <linklist.h>
#include "Ril.h"

#ifdef __cplusplus
extern "C" {
#endif


typedef struct _PDP_CONTEXT_ENTRY
{
    LIST_ENTRY          Node;
    HRESULT             AsyncCommandID;
    RILNDISGPRSCONTEXT  RilNdisGprsContext; 
    PVOID               pCRilInstance;
} PDP_CONTEXT_ENTRY, *PPDP_CONTEXT_ENTRY;

typedef enum oemndiseventtype_tag
{
  OEM_NDIS_NULL_EVENT,             /* no event available                        */

  /* Events generated by OEM */

  OEM_NDIS_RX_PACKET,             /* Received a packet                          */
  OEM_NDIS_TX_PACKET_COMPLETE,    /* TX packet done - buffer can be reused      */
  OEM_NDIS_IP_CONFIGURATION,      /* NDIS configuration from network            */
  OEM_NDIS_XOFF,                  /* Please stop sending data to me             */
  OEM_NDIS_XON,                   /* Restart sending data to me                 */
  OEM_NDIS_INITIALISE_COMPLETE,   /*Initialise is now complete                  */
  OEM_NDIS_OPEN_COMPLETE,         /* Open is now complete                       */
  OEM_NDIS_CLOSE_COMPLETE,        /* Close is now complete                      */
  OEM_NDIS_REGISTRATION_STATUS,   /* Indicates whether network is available     */
  /* Events generated by RILGSM */

  OEM_NDIS_TX_PACKET,             /* Request to transmit a packet                */
  OEM_NDIS_RX_PACKET_COMPLETE,    /* RX packet complete - buffer can be reused   */
  OEM_NDIS_OPEN_CONNECTION,       /* open the connection                         */
  OEM_NDIS_CLOSE_CONNECTION,      /* close the connection                        */
  OEM_NDIS_REQUEST_BUFFER_STATUS, /* Request the current Rx buffer status        */
  OEM_NDIS_BUFFER_STATUS,         /* Indicates a significant change in buffers   */
  
  OEM_NDIS_NUMBER_OF_EVENTS
} OEMNDISEVENTTYPE;

typedef enum oemndisbufferstatusreason_tag
{
    OEM_BUFFER_STATUS_REASON_REQUEST,           /* Requested by host            */
    OEM_BUFFER_STATUS_REASON_RX_LOST_PACKET,    /* Lost packet due to insufficient packets */
    OEM_BUFFER_STATUS_REASON_RX_HIGH_WATERMARK, /* Rx buffer count exceeds high watermark (maxbuffers - 4) */
    OEM_BUFFER_STATUS_REASON_RX_LOW_WATERMARK   /* Rx buffer count less than 4  */
} OEMNDISBUFFERSTATUSREASON;
   
typedef struct oemndisbufferstatus_tag
{
    OEMNDISBUFFERSTATUSREASON eReason;
    DWORD                     dwMaxRxBuffers;
    DWORD                     dwRxBuffersInUse;
    DWORD                     dwMaxTxBuffers;
    DWORD                     dwTxBuffersQueued;
} OEMNDISBUFFERSTATUS;
    

typedef enum oemndiserroradditionalinfo_tag
{
    OEM_NO_ADDITIONAL_INFO = 0
} OEMNDISADDITIONALERROR;

typedef struct oemndisstatus_tag
{
    DWORD                   dwErrorStatus;
    OEMNDISADDITIONALERROR  AdditionalErrorInfo;
}  OEMNDISSTATUS;

typedef struct oemndisregistrationstatus_tag
{
    BOOL fGsmRegistered;
    BOOL fGprsAttached;
} OEMNDISREGSTATUS;
   
#define NO_SETTING 0xFFFFFFFF
#define NDIS_PASSWORD_MAX_LENGTH 64
#define NDIS_USERNAME_MAX_LENGTH 64

typedef struct oemndisopenrequest_tag
{
  DWORD                cid;  /* channel id to open */

  /* username and password to be used in connecting to the */
  /* GPRS network                                          */
  /* Optional - length == NO_SETTING means none            */

  DWORD          dwUsernameLength;
  char           psUsername[NDIS_USERNAME_MAX_LENGTH];
  DWORD          dwPasswordLength;
  char           psPassword[NDIS_PASSWORD_MAX_LENGTH];

} OEMNDISOPENREQUEST;

#define OEMNDIS_MAX_IP_ADDRESS_LENGTH 16

typedef struct oemndisipaddress_tag
{
  UCHAR length;         /* length 0 means unset */
  UCHAR address[16]; 
} OEMNDISIPADDRESS;

typedef struct oemndisconfiguration_tag
{
  OEMNDISIPADDRESS   ipAddress;
  OEMNDISIPADDRESS   primaryDnsAddress;
  OEMNDISIPADDRESS   secondaryDnsAddress;

  /* others to be defined??? */
} OEMNDISCONFIGURATION;

typedef struct oemndiseventtwo_tag
{
  OEMNDISEVENTTYPE            type;
  union
  {
     int                       null;
    LPRILNDISPACKET            packet_p;
    OEMNDISCONFIGURATION       configuration;
    OEMNDISSTATUS              NdisStatus;   
    OEMNDISOPENREQUEST         open;
    OEMNDISREGSTATUS           regStatus;
    OEMNDISBUFFERSTATUS        bufferStatus;
  } event;
} OEMNDISEVENT;

// Structure used for keeping track of the NDIS channels.
typedef struct oemndischannels_tag
{
    DWORD                dwCid;
    HANDLE               hNdisHandle;
    RILNDISGPRSCONTEXT   RilNdisGprsContext;
    VOID                *dwCrilInstance;
} OEMNDISCHANNELS;


typedef struct oemndisapireference_tag
{
    HRESULT           hrCommandID; // Used for storing the command ID.
    DWORD             ContextID;
    VOID              *dwCrilInstance;
    OEMNDISEVENTTYPE  eEventType;
    HANDLE            hNdisHandle;
    DWORD             dwStatus;
    RILNDISGPRSCONTEXTRESPONSE RilNdisGprsContextResponse;
} OEMNDISAPIREFERENCE;

#define NDIS_ADD_CHANNEL_EVENT_INDEX   0
#define NDIS_STOP_THREAD_INDEX         1
#define PERMANENT_OEMNDIS_EVENTS       2 // The events just listed.

//#if defined (OEM1_DRIVER)
#if defined (OEM2_DRIVER)
#define NDIS_EVENT_PREFIX "TTPMUX_NDIS_NOTIFICATION_EVENT_"
#else
#define NDIS_EVENT_PREFIX "OEM_NDIS_NOTIFICATION_EVENT_"
#endif

#define FIRST_VALID_NDIS_INDEX 0
#define MAX_OEMNDIS_CHANNELS   3     // The number of gprs channels NDIS can open. It should be dynamic.
#define MAX_OEMNDIS_EVENTS     MAX_OEMNDIS_CHANNELS + PERMANENT_OEMNDIS_EVENTS     // The number of notifications (channels) from OEM plus 
// one for interprocess communication and one to kill the thread.

// Structure used with to keep track of events
typedef struct oemndiswaiteventobject_tag
{
    HANDLE      lpNdisEventHandlesPrimary[MAX_OEMNDIS_EVENTS];// Array of event handles waited on for WaitOnMultipleObjects
    HANDLE      lpNdisEventHandlesUpdate[MAX_OEMNDIS_EVENTS]; // Array of event handles waited on for WaitOnMultipleObjects
    HANDLE      lpNdisHandles[MAX_OEMNDIS_EVENTS];            // A array that shadows m_lpNdisEventHandles that maintains the OEM Ndis handles for convenience.
    INT         nObjectCount; // The number of objects used for WaitOnMultipleObjects. It refers to m_lpNdisEventHandles
    HANDLE      hNdisAddChannelEvent;
} OEMNDISWAITEVENTOBJECT;

typedef struct asyncresponse_tag
{
    LIST_ENTRY              Node;   
    OEMNDISAPIREFERENCE     OemNdisApiReference;  
} ASYNCCOMMAND, *PASYNCCOMMAND;

class AsyncResponse
{
public:
    AsyncResponse();
    ~AsyncResponse();
        
    void    AddCommand ( OEMNDISAPIREFERENCE *lpOemNdisApiReference );
    BOOL    ProcessCommand ( const OEMNDISAPIREFERENCE *lpOemNdisApiReference );
    void    RemoveCommand( HRESULT hrCommandID );
    void    RemoveAllCommands ( HANDLE hContextHandle  );

private:
    void    AsyncListLock(void);
    void    AsyncListUnlock(void);

    LIST_ENTRY    m_AsyncPendingList;
    LIST_ENTRY    m_AsyncFreeList;
    CRITICAL_SECTION  m_cs;
    
};

class CRilInstanceNDIS
{
public:
                        CRilInstanceNDIS();
                        ~CRilInstanceNDIS();
    void                Init(PVOID hInstance );
    HRESULT             NdisSendPacket (RILNDISPACKET* lpNdisPacket);
    HRESULT             NdisSetGPRSContextActivated (const RILNDISGPRSCONTEXT *lpNdisSetGprsContextActivated );
    HRESULT             NdisReceivePacketDone (RILNDISPACKET* lpNdisPacket);

private:
    PVOID               m_pCrilInstance;

};

class CRilNDIS
{
public:
                    CRilNDIS();
                    ~CRilNDIS();
    void            NdisRemoveNdisEntry ( HANDLE hNdisHandle );
    void            NdisAddCRilNdisEntry ( HANDLE hNdisHandle, PVOID pCRil  );
    void            NdisAddNdisEntry ( DWORD cid, DWORD dwIndex,  HANDLE hHandle, VOID *hCrilInstance, const RILNDISGPRSCONTEXT *lpRilNdisGprsContext );
    void            NdisRemoveCallbacks ( DWORD ContextID );
    void*           NdisRilInstanceFromHandle( HANDLE hNdisHandle );
    void            NdisRilCallbacksFromCID( DWORD ContextID, PVOID *pCallbackContext, RILNDISRECEIVECALLBACK *pfnRilReceiveCallback, RILNDISTRANSMITCALLBACK *pfnRilTransmitCallback, RILNDISSTATUSCALLBACK *pfnRilStatusCallback );
    HRESULT         NdisGetFreeNdisEntry ( DWORD *lpIndex );
    DWORD           NdisNotifyThread(void);
    HRESULT         NdisAddNotifyEvent(HANDLE hNdisHandle);
    HRESULT         NdisRemoveNotifyEvent(HANDLE hNdisHandle);
    HRESULT         NdisCidFromHandle( HANDLE hNdisHandle, DWORD *lpCid );
    HRESULT         NdisOemNdisOpenRequestFromHandle( HANDLE hNdisHandle, RILNDISGPRSCONTEXT *lpRilNdisGprsContext );
    HRESULT         NdisCRilFromHandle( HANDLE hNdisHandle, PVOID *pCRil );
    HRESULT         NdisHandleFromCid( DWORD cid, HANDLE *hNdisHandle );
    void            NdisConvertConfig ( const OEMNDISCONFIGURATION* lpOemNdisConfig,  RILNDISIPCONFIG* lpRilNdisIpConfig);
    void            NdisCloseAllConnections ( void );
    HANDLE          NdisInterfaceInitialise (DWORD index);
    BOOL            NdisInterfaceShutdown (HANDLE handle);
    BOOL            NdisInterfaceReceiveEvent(HANDLE handle, OEMNDISEVENT *event_p, BOOL *moreEvents_p);
    BOOL            NdisInterfaceTransmitEvent(HANDLE handle, const OEMNDISEVENT *event_p);
    void            NdisShutdownConnection ( HANDLE hHandle );
    void            NdisAllocateCommand ( OEMNDISEVENTTYPE eType, HANDLE hNdisChannelHandle, LPVOID lpCrilInstance, HRESULT CommandID, DWORD ContextID );
    void            NdisRemoveCommand ( HRESULT hrCommandID );
    BOOL            NdisStart ( HANDLE hCancelEvent );
    void            NdisStop( void );
    void            Init(PVOID pHandle );
    BOOL            NdisSupported(void) { return TRUE; };
    void            AddPdpContextEntry( const RILNDISGPRSCONTEXT *pRilNdisGprsContext, HRESULT AsyncCommandID, PVOID pCRilInstance );
    void            RemovePdpContextEntry( PPDP_CONTEXT_ENTRY pPdpContextEntry );
    BOOL            IsPdpContextListEmpty( void );
    PPDP_CONTEXT_ENTRY            GetNextPdpContextEntry(  void );
    void            RemoveAndSignalAllPdpContextEntries ( DWORD ContextID );
    void            LockPdpContextList(void){PdpContextLock();}
    void            UnlockPdpContextList(void){PdpContextUnlock();}
    DWORD           GetRadioXon(void){return m_fXon;}
    void            ProcessNextContextRequest(void);

private:
    void            PdpContextLock(void);
    void            PdpContextUnlock(void);
    BOOL            IsPdpContextLocked(void);
    PPDP_CONTEXT_ENTRY  PdpContextEntryGet(void);
    void            DumpPdpContextList ( void );

    DWORD                           NdisCountEvents(void);

    OEMNDISCHANNELS                 m_rgpNdisChannels[MAX_OEMNDIS_CHANNELS]; // Array of ndis channels in use and available.
    HANDLE                          m_hNdisNotifyThread; // Handle returned from CreateThread
    DWORD                           m_dwNdisNotifyThreadID;
    OEMNDISWAITEVENTOBJECT          m_rgpNdisEvents; // all the info related to the events that NdisNotifyThread waits on.
    CRITICAL_SECTION                m_csNdisEventList;
    AsyncResponse                   m_NdisAsyncCommandList;
    PVOID                           m_pCrilHandle;
    HANDLE                          m_hCancelEvent;
    CRITICAL_SECTION                m_csConnectionList;
    LIST_ENTRY                      m_PdpContextPendingList;
    LIST_ENTRY                      m_PdpContextFreeList;
    CRITICAL_SECTION                m_PdpContextCriticalSection;
    DWORD                           m_fXon;

};

#ifdef __cplusplus
}
#endif



